'use strict'

const http=require('http');
const fs=require('fs');

const fsp = fs.promises

//在浏览器输入:http://localhost:3456/upload?a=123&b=234

function parseBodyHeaders(data){
    let headers={}
    let dsplit=data.split('\r\n').filter(p=>p.length>0)

    let ind;
    let k
    for(let d of dsplit){
        ind=d.indexOf(':')
        if(ind<=0)continue
        
        k=d.substring(0,ind).toLowerCase()

        headers[k]=d.substring(ind+1).trim()//trim把空格全去掉

    }

    let cpd=headers['content-disposition']

    //按照;分割成数组，第一个元素form-data去掉
    let clist=cpd.split('; ').slice(1)

    let name,filename
    
    for(let a of clist){
        ind=a.indexOf('filename="')
        if(ind>=0){
            filename=a.substring(ind+10,a.length-1)//a.length-1:去掉最后一个"
        }else{
            name=a.substring(6,a.length-1)
        }
    }

    return{
        headers,
        name,
        filename
    }
}

/**
 * 
 * @param {Buffer} bodyData 原始的body数据
 * @param {Object} reqHeaders request.headers
 */

function parseBody(bodyData,reqHeaders){

    //content-type:multipart/form-data;boundary=-----34294329
    let ctype=reqHeaders['content-type']

    //拿到分界线boundary
    let bdy=ctype.substring(ctype.indexOf('=')+1)

    //数据中用于分割文件的分界线，前面的'--'是body解析时自动加上的，'\r\n'是换行

    let crlf_bdy=`\r\n--${bdy}`

    //从偏移bdy的长度开始查找下一个分界线的位置
    let data_end_index=bodyData.indexOf(crlf_bdy,crlf_bdy.length)

    //body消息数据中header部分的最后索引
    let header_end_index=bodyData.indexOf('\r\n\r\n',crlf_bdy.length)

    let header_data=bodyData.toString('utf-8',
                                        crlf_bdy.length,
                                        header_end_index)//结束位置

    //解析body数据中的消息头
    let hd=parseBodyHeaders(header_data)

    let fileinfo={
        start:header_end_index+4,//除去\r\n\r\n
        end:data_end_index,
    }
    fileinfo.length=fileinfo.end-fileinfo.start

    return{
        name:hd.name,
        filename:hd.filename,
        headers:hd.headers,
        start:fileinfo.start,
        end:fileinfo.end,
        length:fileinfo.length
    }
}

function parseExtName(filename) {
    if(filename.length < 2) return

    let namesplit = filename.split('.').filter(p=>p.length>0)

    if(namesplit.length<2) return '';

    return `.${namesplit[ namesplit.length-1 ]}`
}


let routerTable={

    GET:{//GET /upload HTTP/1.1获取资源
        '/upload':async(ctx)=>{
            let stm=fs.createReadStream('./upload.html')
            stm.pipe(ctx.res)
            stm.on('end',()=>{
                ctx.res.end()
            })
        }
    },

    POST:{//POST /upload HTTP/1.1创建资源
        '/upload':async(ctx)=>{
            console.log(ctx.files)

            let finfo = ctx.files

            let filename = `${Date.now()}-${parseInt(Math.random()*100000)+100000}`
                            + parseExtName(finfo.filename)

            let fh = await fsp.open(filename, 'w+')

            

            let fret = await fh.write(ctx.rawBody,
                                    finfo.start,
                                    finfo.length,
                                    0)

            // 关闭打开的文件
            fh.close()

            //返回写入的字节数。string或buffer类型，不能是其他类型
            ctx.end( `${fret.bytesWritten}` )
            
           
        }
    }
}

/** ------------------------START SERVER------------------------  */


let serv=http.createServer()

serv.on('request',(request,response)=>{
    let  rm=routerTable[request.method]

    //根据？切割字符串
    let usplit=request.url.split("?")

    let pathname=usplit[0]
    let querystring=usplit[1] || ''//如果usplit[1]不存在，则为空

    if(!rm || !rm[pathname]){
        response.statusCode=404
        response.end('page not found')
        return
    }

    //ctx is context,创建请求上下文对象
    let ctx={
        req:request,
        res:response,
        method:request.method,
        headers:request.headers,
        end:(data,encoding='utf8')=>{
            response.end(data,encoding)
        },
        write:(data,encoding="utf8")=>{
            response.write(data,encoding)
        },
        path:pathname,
        querystring:querystring,
        rawBody:null//原始的body类
    }

    let bufferList=[]
    let totalLength=0

    //可以提交body数据的请求：POST PUT PATCH DELETE（PD开头）

    //不能提交body数据的请求：GET HEAD TRACE OPTIONS，如果提交算是恶意请求
    if('PD'.indexOf(request.method[0])>=0){
        request.on('data',chunk=>{
            totalLength+=chunk.length;
            bufferList.push(chunk)
        })
    }else{
        request.on('data',chunk=>{
            response.statusCode=400
            response.end()
        })
    }

    request.on('end',()=>{
        if(bufferList.length>0){
            ctx.rawBody=Buffer.concat(bufferList,totalLength)
            bufferList=[]
        }
        let ctype=ctx.headers['content-type'] || ''

        if(ctx.rawBody && ctype.indexOf('multipart/form-data')===0)
        {
            ctx.files=parseBody(ctx.rawBody,ctx.headers)
        }
        rm[pathname](ctx)
    })


    
    
})

serv.listen(3456)
